package com.googlecode.animator.view.timeline
{
	import flash.display.DisplayObjectContainer;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	
	import mx.core.Application;
	import mx.core.UIComponent;
	
	/**
	 * Provides basic functionality for all timeline elements. 
	 * @author USER
	 * 
	 */
	public class SnapDraggableObject extends UIComponent implements ISnapDraggableObject
	{
		
		protected var _name:String;
		protected var _hitArea:Sprite;
		protected var _dragging:Boolean;	
		protected var _objectOffset:int;
		protected var _lastPos:int;
		
		private var _isDraggable:Boolean;		
		private var _offsetY:int;
		private var _container:DisplayObjectContainer;
		
		public static const OBJECT_UP:String = "objectUp";
		public static const OBJECT_DOWN:String = "objectDown";
		public static const OBJECT_MOVE:String = "objectMove";
		
		/**
		 * Constructor. 
		 * 
		 */
		public function SnapDraggableObject(w:uint)
		{
			width = w;
			
			_hitArea = new Sprite();
			_hitArea.name = "hArea";			
			_hitArea.graphics.beginFill(0x000000, 0);
			_hitArea.graphics.drawRect(-200, -200, 400, 400);
			
			_dragging = false;
			
			_isDraggable = true;
			
			_objectOffset = 0;
			
			
			// listen for mouse events anywhere within the application
			Application.application.addEventListener(MouseEvent.MOUSE_UP, onMouseUpAnywhere);
			Application.application.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMoveAnywhere);
			
			// listen for mouse down events specifically on this timeline element
			addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
			
		}
		
		/**
		 * Responds to mouse up events anywhere. 
		 * @param evt
		 * 
		 */
		protected function onMouseUpAnywhere(evt:MouseEvent = null):void
		{
			if(_dragging && _isDraggable)
			{
				removeChild(_hitArea);
				stopDrag();
				
				dispatchEvent(new Event(OBJECT_UP, true));
				
				_dragging = false;
			}
			
			
		}
		
		/**
		 * Responds to mouse move events anywhere. 
		 * @param evt
		 * 
		 */
		protected function onMouseMoveAnywhere(evt:MouseEvent):void
		{
			if(_dragging && _isDraggable)
			{
				y = _offsetY;
				
				x = Math.round((_container.mouseX - _objectOffset) / width) * width;

				//Prevent less than 0		
				if(x < 0)
				{
					x = 0;
				}
				
				if(x != _lastPos)
				{
					dispatchEvent(new Event(OBJECT_MOVE, true));
				}
					
				_lastPos = this.x;
			}
		}
		
		/**
		 * Responds to mouse down events on this component. 
		 * @param evt
		 * 
		 */
		protected function onMouseDown(evt:MouseEvent):void
		{
			if(_isDraggable)
			{
				_objectOffset = evt.localX;

				_dragging = true;
				addChild(_hitArea);
				startDrag();
			}
			
			dispatchEvent(new Event(OBJECT_DOWN, true));
		}
		
		/* public function set dragging(value:Boolean):void
		{
			_dragging = value;
		}
		
		public function get dragging():Boolean
		{
			return _dragging;
		} */
		
		/* public function set lastPos(pos:int):void
		{
			_lastPos = pos;
		}
		
		public function get lastPos():int
		{
			return _lastPos;
		} */
		
		/**
		 * Sets the draggability of this component. 
		 * @param value
		 * 
		 */
		public function set isDraggable(value:Boolean):void
		{
			_isDraggable = value;
		}
		
		public function get isDraggable():Boolean
		{
			return _isDraggable;
		}
		
		/**
		 *  
		 * @param value
		 * 
		 */
		public function set offsetY(value:int):void
		{
			_offsetY = value;
		}
		
		public function get offsetY():int
		{
			return _offsetY;
		}
		
		/**
		 * Provides a means of easily retrieving or setting the time this component represents. 
		 * @param t
		 * 
		 */
		public function set time(t:Number):void
		{
			x = width * t;
			//Prevent less than 0		
			if(x < 0)
			{
				x = 0;
			}
			
		}
		
		public function get time():Number
		{
			return Math.round(x / width);
		}
		
		/**
		 * Set the container this object is inside. 
		 * @param c
		 * 
		 */
		public function set container(c:DisplayObjectContainer):void
		{
			_container = c;
		}
		
		/**
		 * Returns the container this object is inside. 
		 * @param c
		 * 
		 */
		public function get container():DisplayObjectContainer
		{
			return _container;
		}
		
		override protected function childrenCreated():void
		{
			super.childrenCreated();
			
			_container = parent;
		}
		
		public function cleanUp():void
		{
			// listen for mouse events anywhere within the application
			Application.application.removeEventListener(MouseEvent.MOUSE_UP, onMouseUpAnywhere);
			Application.application.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMoveAnywhere);
			
			// listen for mouse down events specifically on this timeline element
			removeEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
		}
	}
}